Skip to content

fix(stdlib): ArrayIterator nullable elements + eager Array.filter_map + live for-loop tests - #3749

Merged
aaronvg merged 2 commits into
canaryfrom
aaron/iter-live-view-tests-and-nullable-fix
Jun 12, 2026
Merged

aaronvg merged 2 commits into
canaryfrom
aaron/iter-live-view-tests-and-nullable-fix

Conversation

@aaronvg

@aaronvg aaronvg commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-ups to #3747 (lazy array iterators):

  • Fix nullable-element early termination. ArrayIterator.next matched arr.at(idx) against null to detect the end of iteration, so an array of nullable T containing a null element stopped iterating at the first null. It now bounds-checks by index, so stored null elements are yielded. This was pre-existing, but live iterators flowing through more code paths (including every for loop) made it likelier to bite.
  • Add eager Array.filter_map. Eager filter/map return arrays, but filter_map only existed via .iter().filter_map(fn).collect(). This adds an eager array-returning form, implemented in BAML and mirroring for_each's snapshot-via-slice idiom; the lazy version remains on Iterator.
  • Pin for-loop live-view semantics. [codex] Make array iterators lazy #3747 made ArrayIterator hold the source array instead of a snapshot, and for loops lower through Iterable.iter(), so loops now see mid-loop mutations. That was only tested via explicit .iter(); this adds tests pinning that a push mid-loop is visited and a pop mid-loop terminates cleanly.

Validation

  • INSTA_UPDATE=always cargo insta test --test-runner nextest -p baml_tests -p baml_cli
  • cargo nextest run -p baml_tests --test baml_src (2 passed)
  • cargo nextest run -p baml_tests --lib --test bytecode_format (1599 passed)
  • cargo nextest run -p baml_cli describe (83 passed)
  • git diff --check

🤖 Generated with Claude Code


Note

Medium Risk
Changes core iterator/for-loop semantics for nullable element types and documents live-array mutation during iteration; incorrect bounds logic could affect many call sites.

Overview
Fixes array iteration when elements can be null: ArrayIterator.next now ends on an index past the length instead of treating at() returning null as exhaustion, so nullable arrays yield every slot including stored nulls.

Adds eager Array.filter_map, building a new array via a slice-bounded for loop (same snapshot pattern as for_each); lazy iter().filter_map is unchanged.

New stdlib tests lock in for-loop behavior over live array views (push mid-loop is seen; repeated pop shortens iteration), eager filter_map, and nullable-element iteration/count.

Reviewed by Cursor Bugbot for commit fc9a51f. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added filter_map method for arrays to combine mapping and filtering operations in a single operation.
  • Bug Fixes

    • Fixed iterator behavior to correctly yield null elements in arrays with nullable types, rather than treating them as iteration endpoints.
  • Tests

    • Added comprehensive iterator test coverage for array mutations and nullable element handling.

…filter_map; pin live for-loop semantics

Follow-ups to #3747 (lazy array iterators):

- Fix ArrayIterator.next to bounds-check by index instead of matching
  `at()` against null, so arrays of nullable T containing null elements
  iterate all elements rather than terminating early at the first null.
- Add eager `Array.filter_map` returning `U[]`, restoring symmetry with
  eager `filter`/`map` (lazy version remains `iter().filter_map(fn)`).
- Add baml_src tests pinning that `for` loops are a live view of the
  source array (pushes mid-loop are visited; pops mid-loop terminate
  cleanly), plus coverage for the nullable-element fix and eager
  filter_map.

Co-Authored-By: Claude Fable 5 <[email protected]>
@vercel

vercel Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jun 12, 2026 1:13am
promptfiddle Ready Ready Preview, Comment Jun 12, 2026 1:13am
promptfiddle2 Ready Ready Preview, Comment Jun 12, 2026 1:13am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e4299fc7-807e-42e7-8521-6ba17916a599

📥 Commits

Reviewing files that changed from the base of the PR and between 725edd0 and 88de9b5.

⛔ Files ignored due to path filters (9)
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/baml_src/iter.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • baml_language/crates/baml_builtins2/baml_std/baml/containers.baml
  • baml_language/crates/baml_builtins2/baml_std/baml/ns_iter/iter.baml
  • baml_language/crates/baml_tests/baml_src/ns_iter/iter.baml

📝 Walkthrough

Walkthrough

This PR adds Array<T>.filter_map, a new container method that maps and filters array elements using a callback producing nullable outputs. It also fixes ArrayIterator<T>.next to use explicit bounds checking instead of null matching, enabling correct iteration over arrays with nullable elements. The change includes comprehensive test coverage for mutation visibility during iteration and filter_map behavior.

Changes

Array iteration and filter_map enhancement

Layer / File(s) Summary
Iterator semantics fix for nullable elements
baml_language/crates/baml_builtins2/baml_std/baml/ns_iter/iter.baml
ArrayIterator<T>.next now performs explicit bounds checking with self.idx >= self.arr.length() before retrieving the element, allowing nullable T elements to be yielded without being conflated with iteration termination.
Array.filter_map method implementation
baml_language/crates/baml_builtins2/baml_std/baml/containers.baml
New Array<T>.filter_map<U, E> method accepts a callback that produces U? and returns a new array containing only non-null mapped values. Implementation iterates the source array and collects results without mutating self.
Iterator semantics and filter_map test coverage
baml_language/crates/baml_tests/baml_src/ns_iter/iter.baml
Tests validate iterator mutation visibility during for loops (push/pop during iteration), eager filter_map behavior over integer arrays, and iteration over nullable array elements with element count, null count, sum of non-null values, and iterator count tracking.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant Array as Array[T]
  participant Iterator as ArrayIterator[T]
  participant Callback as fn(T)->U?
  participant Result as Array[U]
  
  Caller->>Array: filter_map(fn)
  loop for each element
    Array->>Iterator: next()
    Iterator-->>Array: element (or Done)
    Array->>Callback: fn(element)
    Callback-->>Array: U? (mapped value)
    Array->>Result: append if not null
  end
  Array-->>Caller: return Array[U]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • BoundaryML/baml#3747: Related concurrent changes to Array container helper methods and ArrayIterator semantics in iterator behavior.

Poem

🐰 A rabbit hops through arrays clear,
Now filter_map brings joy near!
Null elements won't fool the way,
Bounds check rules the iteration day! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the three main changes: fixing nullable element handling in ArrayIterator, adding eager Array.filter_map, and adding test coverage for for-loop live-view semantics.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aaron/iter-live-view-tests-and-nullable-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

@vercel
vercel Bot temporarily deployed to Preview – beps June 12, 2026 00:55 Inactive
@aaronvg
aaronvg enabled auto-merge June 12, 2026 00:55
Co-Authored-By: Claude Fable 5 <[email protected]>
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 12, 2026 00:57 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 12, 2026 00:58 Inactive
@github-actions

Copy link
Copy Markdown

No description provided.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 12, 2026 01:04 Inactive
@aaronvg
aaronvg added this pull request to the merge queue Jun 12, 2026
Merged via the queue into canary with commit 975e4f9 Jun 12, 2026
52 checks passed
@aaronvg
aaronvg deleted the aaron/iter-live-view-tests-and-nullable-fix branch June 12, 2026 01:18

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle2 — fc9a51fd Deployed Jun 12, 2026 by vercel[bot]
Preview – beps — fc9a51fd Deployed Jun 12, 2026 by vercel[bot]
Preview – promptfiddle — fc9a51fd Deployed Jun 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant